`timescale 1ns / 1ps
`define DIR_OUT 1
`define DIR_IN  0


module A_sp128_master(
		  MAIN_CLK,
		  LINK_OK,  
		  DIR_DATA,
		  DIR_REMOTE,
		  SUBSCRIBER_ADDR,
		  S_CLK,                
		  S_DATA_IN,S_DATA_OUT, 
		 
		  IN_REG_1,  IN_REG_2,  IN_REG_3,  IN_REG_4,  CMD_IN, 
		  OUT_REG_1, OUT_REG_2, OUT_REG_3, OUT_REG_4, CMD_OUT  
    );
	
parameter GAP_PAUSE = 8'd200;	 	
 
output DIR_DATA;
output DIR_REMOTE;	
	
	
	
input [3:0]SUBSCRIBER_ADDR;	
	
input     	 MAIN_CLK;
output reg	 LINK_OK;
output reg   S_CLK;    
input     	 S_DATA_IN;  
inout    	 S_DATA_OUT; 
	 
output reg	 [31:0]IN_REG_1,  IN_REG_2,  IN_REG_3,  IN_REG_4;
input     	 [31:0]OUT_REG_1, OUT_REG_2, OUT_REG_3, OUT_REG_4;
	 
output reg [7:0]CMD_IN;
input      [7:0]CMD_OUT;	 
	 
wire fDataIn; 



reg [7:0]startCmd;
initial startCmd = 8'h91; //[7:4]=0x9 - master->slave; [7:4]=0x6 - slave->master;

wire [151:0]W_OUT_REG_;
assign W_OUT_REG_[7  :0  ] = startCmd;
assign W_OUT_REG_[39 : 8 ] = OUT_REG_1;
assign W_OUT_REG_[71 :40 ] = OUT_REG_2;
assign W_OUT_REG_[103:72 ] = OUT_REG_3;
assign W_OUT_REG_[135:104] = OUT_REG_4;
assign W_OUT_REG_[143:136] = CMD_OUT;
assign W_OUT_REG_[151:144] = crc8;
 

wire [7:0]crcIn = inReg[151:144]; 
 	
//frFilter	clkFl (MAIN_CLK, S_CLK, s_clk); //in slave mode
frFilter dataFl(MAIN_CLK, S_DATA_IN, fDataIn); 	
	
//---------------------------------------------------------		
reg clk;
always@(posedge MAIN_CLK)clk <= ~clk;  
 
 
reg       prepClk;
reg[7  :0]clkCnt;
reg[2  :0]clkAut;
reg[7  :0]clkPause;
reg[7  :0]crc8;
reg[7  :0]crcShft; 
reg[7  :0]bitCnt;
reg[7  :0]rstOutCnt;
reg[143:0]crcReg;
reg[151:0]inReg;
reg[7  :0]crcCnt;  
//---- SHIFT OUT DATA --------------	 
reg inOutTrigger;
assign DIR_DATA = inOutTrigger;
assign DIR_REMOTE = ~inOutTrigger; 
 
task TSK_SEND_RESEIVE_DATA;
	begin
		if(S_CLK != prepClk)begin
			prepClk <= S_CLK;
			rstOutCnt<=0;  
  			
			if(S_CLK)begin
				if(inOutTrigger)sData<=W_OUT_REG_[bitCnt];
			end else begin
				bitCnt<=bitCnt+1'b1;
			end
			
		end else begin
			rstOutCnt<=rstOutCnt+1;
			if(rstOutCnt > GAP_PAUSE - 8'd20)begin
				bitCnt<=0;
				rstOutCnt<=0;				
			end
		end	
			
	end
endtask	
 
task TSK_S_CLK_AUTOMAT;
	begin
		clkAut  <=clkAut+1'b1;
		case(clkAut)
			2 : S_CLK  <= 1;
			5 : S_CLK  <= 0;
			7 : clkCnt <= clkCnt+1; 
		endcase 
	end
endtask

reg sData;
assign S_DATA_OUT = inOutTrigger ? sData : 1'bZ;
always@(posedge MAIN_CLK)begin
    inReg[bitCnt]<=fDataIn;

	if(crcCnt < 18)begin
	   crc8   <= crc8+crcReg[143:136];
		crcCnt <=crcCnt+1; 
		crcReg <= crcReg << 8;
	end	

	if(bitCnt == 7)begin
		if(startCmd[7:4] == 4'h9)begin
			crcCnt <= 0;
			crc8   <= 8'hA5;
			crcReg <= W_OUT_REG_[143:0];//in slave  - [135:0]
		end
	end
	if(!bitCnt)begin	
		LINK_OK      <= 0;
	end	
	
	if(!inOutTrigger)begin
		if(bitCnt == 143)begin
			crcCnt <= 0;
			crc8   <= 8'hA5;
			crcReg <= {inReg[143:8], 8'h00};
		end	
		if(bitCnt == 151)begin
			if(crc8 == crcIn)begin
				LINK_OK <= 1;				
				IN_REG_1 <= inReg[39 :8  ];
				IN_REG_2 <= inReg[71 :40 ];
				IN_REG_3 <= inReg[103:72 ];
				IN_REG_4 <= inReg[135:104];
				CMD_IN   <= inReg[143:136];
			end
			 
		end			
	end
end



always@(posedge MAIN_CLK)begin
   TSK_SEND_RESEIVE_DATA;
end
  
//------------------------------------  

always@(posedge clk)begin
    if(clkPause>0)begin
		clkPause <= clkPause-1'b1;	 
	end	else begin
		
		if(clkCnt==8)begin
			if(startCmd[7:4] == 4'h6)inOutTrigger <= 0;
			startCmd[7:4] <= ~startCmd[7:4];
			startCmd[3:0] <= SUBSCRIBER_ADDR[3:0];
		end   		
		
		if( clkCnt==8  ) begin clkPause<=20; clkCnt <= clkCnt+1; end 
		if((clkCnt==41 )||
		   (clkCnt==74 )||
		   (clkCnt==107)||
		   (clkCnt==140)||
		   (clkCnt==149)) begin clkPause<=10; clkCnt <= clkCnt+1; end     
		
		if (clkCnt==8'd158)begin
			clkPause<=GAP_PAUSE; clkCnt <= 0;  crcShft <= 0; inOutTrigger <= 1;
		end
		
        TSK_S_CLK_AUTOMAT; 
	end
end
 
	
	
	
endmodule	
	
	
	